﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace B121B {
    /// <summary>
    /// Truck class
    /// </summary>
    public class Truck : Vehicle, IHasHeightAndWeight, IHasLoadCapacity, IRequireBigLicense {
        /// <summary>
        /// Vehicle constructor
        /// </summary>
        /// <param name="brand">Brand</param>
        /// <param name="model">Model</param>
        /// <param name="km">Distance driven</param>
        /// <param name="year">Production year</param>
        /// <param name="price">Price</param>
        /// <param name="motorSize">Size of motor</param>
        /// <param name="km_l">Travel distance on 1 liter of fuel</param>
        /// <param name="fueltype">Fueltype</param>
        /// <param name="loadCapacity">Load capacity</param>
        /// <param name="hasBed">Does it have a bed</param>
        /// <param name="license">License of driver</param>
        /// <param name="height">Height</param>
        /// <param name="weight">Weight</param>
        public Truck(string brand, string model, int km, DateTime year, int price, double motorSize, double km_l, Fuel fueltype, int loadCapacity, bool hasBed, DriversLicense license, double height, int weight)
            : base(brand, model, km, year, price, motorSize, km_l, fueltype) {
            LoadCapacity = loadCapacity;
            HasBed = hasBed;
            Height = height;
            Weight = weight;
            License = license;
            VehicleType = VehicleTypes.Truck;
        }

        #region Properties
        /// <summary>
        /// Fueltype
        /// </summary>
        public override Fuel FuelType {
            get { return _FuelType; }
            protected set {
                if (value != Fuel.Diesel) { // Check for valid fuel type
                    throw new ArgumentException("Trucks run on diesel!"); // Trucks run on diesel, as per assignment
                } else {
                    _FuelType = value;
                }
            }
        }
        private Fuel _FuelType;

        /// <summary>
        /// Max speed
        /// </summary>
        public override int MaxSpeed { get { return 95; } } // Max speed is locked at 95, as per assignment

        /// <summary>
        /// Motor size
        /// </summary>
        public override double MotorSize {
            get { return _MotorSize; }
            set {
                if (!IsMotorSizeOkay(5.0, 15.0, value)) { // Check for valid size
                    throw new ArgumentOutOfRangeException();
                } else {
                    _MotorSize = value;
                }
            }
        }
        private double _MotorSize;

        /// <summary>
        /// Load capacity
        /// </summary>
        public int LoadCapacity {
            get { return _LoadCapacity; }
            set {
                if (value < 0) { // Checks for valid capacity
                    throw new ArgumentOutOfRangeException("The load capacity cannot be negative");
                } else {
                    _LoadCapacity = value;
                }
            }
        }
        private int _LoadCapacity;

        /// <summary>
        /// Does it have a bed
        /// </summary>
        public bool HasBed { get; set; }

        /// <summary>
        /// Height of the truck (in meters)
        /// </summary>
        public double Height {
            get { return _Height; }
            set {
                if (value < 0) { // Check for valid height
                    throw new ArgumentOutOfRangeException("A truck cannot have a negative height");
                } else {
                    _Height = value;
                }
            }
        }
        private double _Height;

        /// <summary>
        /// Weight of the truck
        /// </summary>
        public int Weight {
            get { return _Weight; }
            set {
                if (value < 0) { // Check for valid weight
                    throw new ArgumentOutOfRangeException("A truck cannot have a negative weight");
                } else {
                    _Weight = value;
                }
            }
        }
        private int _Weight;

        /// <summary>
        /// License of the driver
        /// </summary>
        public DriversLicense License {
            get { return _License; }
            set {
                if (value < DriversLicense.C) { // Check for valid license
                    throw new ArgumentException("Driver must have at least a C license"); // A driver must have at least a C license to drive a truck, as per assignment
                } else {
                    _License = value;
                }
            }
        }
        private DriversLicense _License;
        #endregion

        #region Override Equals
        public override bool Equals(object obj) {
            if (obj == null) { return false; } // Check for null

            // We don't check for reference equality

            if (this.GetType() != obj.GetType()) { return false; } // Same type?

            return Equals((Truck)obj); // More specific check
        }
        public bool Equals(Truck obj) {
            if (obj == null) { return false; }

            return // Check all values
                base.Equals(obj) &&
                this.LoadCapacity == obj.LoadCapacity &&
                this.HasBed == obj.HasBed &&
                this.Height == obj.Height &&
                this.Weight == obj.Weight;
        }
        public override int GetHashCode() {
            return base.GetHashCode(); // We do not check has code, as we check on values only
        }

        public static bool operator ==(Truck obj1, Truck obj2) {
            if (ReferenceEquals(obj1, null)) {
                return ReferenceEquals(obj2, null); // Both null, equal, otherwise not
            }
            return obj1.Equals(obj2);
        }
        public static bool operator !=(Truck obj1, Truck obj2) {
            return !(obj1 == obj2);
        }
        #endregion

        /// <summary>
        /// Show information about the truck, formatted for console output
        /// </summary>
        /// <returns>Information about the truck</returns>
        public override string ToString() {
            return base.ToString() + Environment.NewLine +
                "  Load capacity: " + LoadCapacity + " kg" + Environment.NewLine +
                "  Bed: " + (HasBed ? "Yes" : "No") + Environment.NewLine +
                "  Height: " + Height + " m" + Environment.NewLine +
                "  Weight: " + Weight + " kg" + Environment.NewLine +
                "  Drivers license: " + License;
        }
    }
}